/**
 * @auther jiagnqifan
 * @since 2016-03-31
 */

var Models = require('../../../../models');
var ProductConfig = Models.ProductConfig;
var Product = Models.Product;
var Cert = Models.Cert;

var logger = require('log4js').getLogger();
var EventProxy = require('eventproxy');
var tools = require('../../../../common/tools.js');
var zip = require('../../../../common/zip.js');
var fs = require('fs');
var path = require('path');
var request = require('request');
var config = require('../../../../config.json');
var url = require('url');
var builder_url = url.format(config.app.builder);
var spaces_url = builder_url + '/spaces';
var product_repo = config.product_repo;

//TODO
/*
 1. 证书配置文件生成

 */



//util methods

function tryCallback(callback, err, data) {
    if (err) {
        logger.error(err);
    }
    if ('function' == typeof callback) {
        callback(err, data);
    }
}


function setBuildState(build, state, callback) {
    logger.info('change state of ' + build._id + ' to ' + state);
    build.state = state;
    build.save(callback);
}

//=============================================================


/**
 1. 获取token
 2. 上传文件
 2. 发起构建
 *
 */
function start(build, callback) {

    var ep = new EventProxy();

    //err handle
    ep.fail(function (message) {
        setBuildState(build, 'error');
        tryCallback(callback, message);
    });

    //set state to readying, then to start
    setBuildState(build, 'readying', function (err, data) {
        if (err) {
            return ep.throw('error occurs when change build state to readying.');
        }
        //messageBroker.emit('build_state_update',...)
        ep.emit('state_change_to_readying');
    });

    //do ready after state change to readying
    ep.on('state_change_to_readying', function ready() {

        logger.info('state_change_to_readying');

        //find project dir from product config

        var product_config_ids = build.config.product_configs;
        if (!product_config_ids || !product_config_ids.length) {
            var message = 'cannot start build because no product config.';
            return tryCallback(callback, message);
        }
        //移动构建目前支持一次构建一个产品, 没想好如果发起多次构建的话进度如何显示
        var product_config_id = product_config_ids[0];

        ProductConfig.findById(product_config_id, function (err, product_config) {

            logger.info('product config:' + product_config_id + ' found.');

            if (err || !product_config) {
                return ep.throw('cannot find product_config:' + product_config_id);
            }

            var projects = product_config.projects;

            if (!projects || !projects.length) {
                var message = 'cannot start build because no product config.';
                return ep.throw(message);
            }
            //
            var temp_dir = null;
            try {
                temp_dir = tools.createTempDirSync();
            } catch (e) {
                return ep.throw('创建临时目录失败' + (e.message ? e.message : e));
            }

            //use this for token of build
            var spaceID = null;

            getSpace();

            function getSpace() {
                request.post(spaces_url).on('response', function (response) {
                    tools.pareseResponseJSON(response, function (err,response) {
                        if (err || 200 != response.statusCode) {
                            setBuildState(build, 'error');
                            return tryCallback(callback, 'get sapce from ' + spaces_url + ' faild.');
                        } else {
                            spaceID = response.body.spaceID;
                            if (!spaceID) {
                                return tryCallback(callback, 'get sapce from ' + spaces_url + ' faild.');
                            }
                            ep.emit('space_ready');
                        }
                    })
                }).on('error', function (err) {
                    logger.error(err);
                });
            }

            ep.on('space_ready', function () {

                logger.info('space_ready');
                var getAllProjects = require('./app_android.js').getAllProjects;
                getAllProjects(product_config.project,function(err) {
                    if (err) {
                        return ep.throw('get projects in master workspace error');
                    } else {

                        var project = projects[0];
                        //var location = config.workspace.workspeces_path + path.sep + project.location; //新模式下 这里直config.temp_workspace + path.sep + project.location;
                        var location = config.master_workspaces + path.sep + project.location;
                        var fileName = 'project.zip';
                        var project_file_path = path.join(temp_dir, fileName);

                        //  var url = spaces_url+"/"+spaceID+'/input/'+fileName;
                        //  tools.upload(project_file_path, url, ep.done('project_uploaded'));
                        console.log(location);
                        console.log(project_file_path);

                        zip.zip(location, project_file_path, function (err, data) {
                            if (err) {
                                return ep.throw('zip file faild.');
                            }
                            var url = spaces_url + "/" + spaceID + '/input/' + fileName;
                            tools.upload(project_file_path, url, ep.done('project_uploaded'));
                        });
                    }
                });
            });
            var detail = product_config.detail;
            var cert_id = detail.certificate;
            var cert = null;
            ep.on('project_uploaded', function () {
                logger.info('project_uploaded');
                ep.on('cert_find', function (data) {
                    cert = data;
                    var files = data.files;
                    var P12File = files.P12File;
                    var provisionFile = files.provisionFile;
                    var url = spaces_url + "/" + spaceID + '/input/';
                    tools.upload(P12File.file_path, url + P12File.file_name, ep.done('P12File_uploaded'));
                    ep.on("P12File_uploaded",function(){
                        logger.info("P12File_uploaded");
                        tools.upload(provisionFile.file_path, url + provisionFile.file_name, function(err){
                            if(err){
                                logger.error("provisionFile upload failed");
                                logger.error(err);
                            }
                            ep.emit('provisionFile_uploaded')
                        })
                    });
                    ep.on("provisionFile_uploaded", ep.done('cert_uploaded'));
                });

                if (cert_id == "default") {
                    logger.info(product_config.name + " use default cert");
                    ep.emit('cert_uploaded');
                }else if(typeof(cert_id) == "undefined"){
                    logger.info(product_config.name + " didn't choose cert");
                    ep.emit('cert_uploaded');
                } else {
                    Cert.findById(cert_id, ep.done('cert_find'));
                }


                ep.after('cert_ready', function (results) {
                    if (_.indexOf(results, false) > -1) {
                        return ep.throw('ready cert failed.');
                    }
                    ep.emit('cert_all_ready');
                });
            });

            ep.on('cert_uploaded', readyJSON);

            function readyJSON() {

                logger.info('cert_uploaded');

                var data = {
                    "android": {
                        "isBuild": "false",
                        "isDefault": "true",
                        "keystoreFilename": "project.keystore",
                        "keystorePassword": "123"
                    },
                    "ios": {
                        "isDefault": "true",
                        "isBuild": "true",
                        "p12Filename": "project.p12",
                        "p12Password": "P@ssw0rd",
                        "ppID": "nectardefault",
                        "ppFilename": "project.mobileprovision"
                    }
                };
                if (cert) {
                    data = {
                        "android": {
                            "isBuild": "false",
                            "isDefault": "true",
                            "keystoreFilename": "project.keystore",
                            "keystorePassword": "123"
                        },
                        "ios": {
                            "isDefault": "false",
                            "isBuild": "true",
                            "p12Filename": cert.files.P12File.file_name,
                            "p12Password": cert.extend_info.P12Password,
                            "ppID": cert.files.provisionFile.file_name,
                            "ppFilename": cert.extend_info.provisionID
                        }
                    };
                }
                    var json_file_path = path.join(temp_dir, 'sign_info.json');
                    fs.writeFile(json_file_path, JSON.stringify(data), function (err) {
                        if (err) {
                            return ep.throw(err);
                        } else {
                            ep.emit('json_ready', json_file_path);
                        }
                    });



                ep.on('json_ready', function (json_file_path) {

                    logger.info('json_ready');

                    var fileName = 'sign_info.json'
                    var url = spaces_url + "/" + spaceID + '/input/' + fileName;
                    tools.upload(json_file_path, url, ep.done('json_uploaded'));

                });
                ep.on('json_uploaded', function () {

                    logger.info('all_uploaded');
                    var begin_url = builder_url + '/execute?task=buildnative&space=' + spaceID + '&action=begin';
                    request.get(begin_url).on('response', function (response) {
                        logger.info(response);
                        tools.pareseResponseJSON(response, function (err , response) {
                            if (err || 200 != response.statusCode) {
                                setBuildState(build, 'error');
                                return tryCallback(callback, 'begin build ' + build.id + ' sapce faild.');
                            } else {
                                ep.emit('ready_completed', spaceID);
                            }
                        });
                    })
                })
            }
        })
    });


    ep.on('ready_completed', function (spaceID) {

        logger.info('ready_completed');

        build.token = spaceID;
        build.save(function (err, data) {
            if (err) {
                return ep.throw('error occurs when set token of build [' + build._id + '] to[' + spaceID + '].');
            }
            setBuildState(build, 'building', ep.done('state_change_to_building'));
        });

    })

    ep.on('state_change_to_building', function () {
        //messageBroker.emit('build_state_update',...)
        logger.info('state_change_to_building');

        tryCallback(callback, null, build);
    })


    //make temp  workspace
    //zip project

    //prepare .json file
    //zip file

}

function tryComplete(build, callback) {
    getIsComplete(build, function (err, completed) {
        logger.info(build._id + ' completed:' + completed);
        if (err) {
            logger.error(err);
            if ('function' === typeof callback) {
                callback(err);
            }
            return;
        }

        if (completed) {
            complete(build, callback);
        }
    })

}
//check is comlete form builder server
function getIsComplete(build, callback) {
    getProgressInfo(build, function (err, info) {
        if (err) {
            logger.error(err);
            callback(err);
        }else if(info){
            logger.info(info);
            var state = info.state;
            callback(null, 2 == state || state < 0);
        }
    });
}

function getProgressInfo(build, callback) {
    var url = builder_url + '/query/spaces/' + build.token;
    request(url, function (err, response, body) {
        logger.info(body);
        logger.info(err);
        logger.info(response.statusCode);
        if (!err && response.statusCode == 200) {
            logger.info('true');
            logger.info(JSON.parse(body));
            callback(null, JSON.parse(body));
        } else {

            logger.info('false');
            callback(err ? err : 'statusCode:' + response.statusCode);
        }
    });
}

//get hundred percent of progress, return integer
function getProgress(build, callback) {
    callback(null, 0);
}

function cancel(build, callback) {

}
function cancelable(build, callback) {
    callback(null, false);
}

//do something after complete
/**
 * 1.下载文件
 *
 */
function complete(build, callback) {

    var ep = new EventProxy();

    //prepare. set err handler
    ep.fail(function (err) {
        logger.err(err);
        callback(err);
    });


    //step1. change state to completing
    ep.on('begin', function () {
        logger.info('set state to completing.[' + build._id + ']');
        build.state = 'completing';
        build.save(function (err, data) {
            if (err) {
                return ep.throw(err);
            }
            build = data;
            //messageBroker.emit('build_state_update',...)
            ep.emit('state_change_to_completing');
        });

    });

    //step2. check result
    ep.on('state_change_to_completing', function () {
        getProgressInfo(build, function (err, info) {
            if (2 == info.state) {
                logger.info('set result to success.[' + build._id + ']');
                build.result = 'success';
                build.save(function (err, data) {
                    if (err) {
                        return ep.throw(err);
                    }
                    ep.emit('result_is_success');
                });
            } else {
                logger.info('set result to failed.[' + build._id + ']');
                build.result = 'failed'
                build.save(function (err, data) {
                    if (err) {
                        return ep.throw(err);
                    }
                    //messageBroker.emit('build_state_update',...)
                    ep.emit('completed');
                });
            }
        });
    });

    //step3. find product config
    ep.on('result_is_success', function () {
        getProgressInfo(build, function (err, info) {
            if (info.state < 0) {
                build.result = 'failed'
                build.save(function (err, data) {
                    if (err) {
                        return ep.throw(err);
                    }
                    //messageBroker.emit('build_state_update',...)
                    ep.emit('completed');
                });
            } else {
                logger.info('set result to failed.[' + build._id + ']');
                var product_config_id = build.config.product_configs[0];
                ProductConfig.findById(product_config_id, function (err, product_config) {
                    if (err || !product_config) {
                        return ep.throw('can not find product config:' + product_config_id);
                    } else {
                        ep.emit('product_config_found', product_config);
                    }
                });
            }
        });

    })


    //step4. download file
    ep.on('product_config_found', function (product_config) {
        logger.info('product_config_found');
        var url = builder_url + '/spaces/' + build.token + '/nectar.zip';
        var dir = path.join(product_repo, build._id.toString());
        try {
            fs.accessSync(product_repo, fs.R_OK);
        } catch (e) {
            fs.mkdirSync(product_repo);
        }
        tools.ensureDirSync(dir);
        var file_path = path.join(dir, 'nectar.zip');
        tools.download(url, file_path, function (err) {
            if (err) {
                return ep.throw(err);
            }
            ep.emit('file_downloaded', file_path, product_config);
        });
    });


    //step5. add product info to db
    ep.on('file_downloaded', function (file_path, product_config) {
        logger.info('file_downloaded');
        var product = new Product();
        product.config = product_config._id;
        product.version = product_config.version;
        product.url = 'file:' + file_path;
        product.save(function (err, data) {
            if (err) {
                return ep.throw(err);
            }
            ep.emit('product_created');
        });
    })

    //step6. change build state to completed
    ep.on('product_created', function () {
        logger.info('product_created');
        build.state = 'completed';
        build.save(function (err, data) {
            if (err) {
                return ep.throw(err);
            }
            ep.emit('completed', data._id);
        });
    });

    //step7. callback
    ep.on('completed', function (product_id) {
        logger.info('completed. build_id:' + build._id + ", product_id: " + product_id);
        tryCallback(callback, null, product_id);
    });

    ep.emit('begin');
}


//Build Type Interfaces
exports.start = start;
exports.cancel = cancel;
exports.getProgress = getProgress;
exports.tryComplete = tryComplete;
exports.cancelable = cancelable;
